package com.younion.task;

import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.google.common.collect.Maps;
import com.younion.business.IMembercardServiceService;
import com.younion.business.IMessageService;
import com.younion.business.INotificationTaskLogService;
import com.younion.business.IRegisterUserService;
import com.younion.business.ISendMsgService;
import com.younion.common.constants.Template;
import com.younion.common.constants.TemplateScope;
import com.younion.common.constants.TemplateTargetType;
import com.younion.common.exception.BaseException;
import com.younion.util.YounionUtil;
import com.younion.vo.MemberCardVO;
import com.younion.vo.MembercardServiceVO;
import com.younion.vo.MessageVO;
import com.younion.vo.MsgTemplateVO;
import com.younion.vo.NotificationTaskLogVO;
import com.younion.vo.RegisterUserVO;
import com.younion.vo.SendMsgVO;

import cpcns.jhsks.util.MapCollectionUtils;

public class ServicePlanHandlerTask extends Task {

    private static Logger            logger          = LoggerFactory.getLogger(ServicePlanHandlerTask.class);
    
    //生日提醒发送时间（整数） 默认： 10点发送
    private Integer sendBirthDayMessageHour = 10;
    //沉默提醒发送时间（整数） 默认： 10点发送
    private Integer sendSlientMessageHour = 10;
    //提醒开关
    private Boolean enableBirthDay = true;
    private Boolean enableNoCost = true;
    private Boolean enableNoRecharge = true;
    private Boolean enableLessRemain = true;
    private Boolean enableRealTime = true;
    //无消费的天数（整数） 默认： 30天内无消费刚下发提醒
    private Integer noCostTime = 30;
    //无充值的天数（整数） 默认： 30天内无充值刚下发提醒
    private Integer noRechargeTime = 30;
    //余额不足的标准线
    private Integer noLessRemainCount = 100;
    //无消费提醒次数
    private Integer noCostCount = 30;
    //无充值提醒次数
    private Integer noRechargeCount = 30;
    //余额不足提醒次数
    private Integer noLessRemainTime = 5;
    //余额不足提醒次数的时间间隔 如30天内提醒5次
    private Integer noLessRemainRange = 30;
    private String noCostTemplate = null;
    private String noRechargeTemplate = null;
    private String LessRemainCountTemplate = null;
    
    
	@Autowired
	private ISendMsgService sendMsgService = null;
	
	@Autowired
	private IMembercardServiceService membercardServiceService = null;
	
	@Autowired
	private IMessageService messageService = null;
	
	@Autowired
	private INotificationTaskLogService notificationTaskLogService = null;
	
	@Autowired
	private IRegisterUserService registerUserService = null;
	

	@Override
    public void work() {
        logger.info("Handle membercard service begin");
        try{
        	if(enableBirthDay){
        		handleBirthDayService();
        	}
        	if(enableNoCost){
        		handleNoCostService();
        	}
        	if(enableNoRecharge){
        		handleNoRechargeService();
        	}
        	if(enableLessRemain){
        		handleLessRemain();
        	}
        	if(enableRealTime){
        		handleRealTimeService();
        	}
        }catch(Exception e){
        	logger.info("Service task handler catch exception");
        	logger.debug(e.toString());
        }
        logger.info("Handle membercard service end");
    }
    
    private void handleRealTimeService() throws Exception{
    	Collection<MembercardServiceVO> noCostMemberCards = retrieveRealTimeMemberCards();
    	logger.info("Found " + noCostMemberCards.size() + " real time service");
    	for (Iterator<MembercardServiceVO> iterator = noCostMemberCards.iterator(); iterator.hasNext();) { 
    		MembercardServiceVO service = (MembercardServiceVO) iterator.next(); 
    		String content = YounionUtil.generateMessageContent(service.getTemplate().getContent(), service.getMemberCard());
    		saveMessage(service, service.getSendTime(), content, "");
    	}
    }

	private void saveMessage(MembercardServiceVO service, Date sendTime,String content, String logTitle) throws Exception {
		String msgType = service.getMsgType();
		if(StringUtils.isBlank(msgType)){
			msgType = service.getTemplate().getScope();
		}
		if(TemplateScope.MSG.getName().equals(msgType)){
			logger.info("Send " +logTitle +" notification message for " + service.getMemberCard().getMemberName());
			messageService.save(createMSG(sendTime, service.getTemplate(), service.getMemberCard(), content));
		}else if(TemplateScope.SMS.getName().equals(msgType)){
			logger.info("Send " +logTitle +" notification sms for " + service.getMemberCard().getMemberName());
			sendMsgService.save(createSMS(sendTime, service.getTemplate(), service.getMemberCard(), content));
		}else{
			logger.info("Send " +logTitle +" notification sms and message for " + service.getMemberCard().getMemberName());
			sendMsgService.save(createSMS(sendTime, service.getTemplate(), service.getMemberCard(), content));
			messageService.save(createMSG(sendTime, service.getTemplate(), service.getMemberCard(), content));
		}
		NotificationTaskLogVO log = new NotificationTaskLogVO(service, new Date(), sendTime, service.getMemberCard(), service.getTemplate());
		notificationTaskLogService.save(log);
	}
    
    private void handleBirthDayService() throws Exception{

    	Collection<MembercardServiceVO> birthDayComeMemberCards = retrieveBirthDayComeMemberCards();
    	logger.info("Found " + birthDayComeMemberCards.size() + " Birth day guys");
		for (Iterator<MembercardServiceVO> iterator = birthDayComeMemberCards.iterator(); iterator.hasNext();) { 
    		MembercardServiceVO service = (MembercardServiceVO) iterator.next(); 
    		String targetType = service.getTemplate().getTargetType();
    		logger.info("Handle birthday notification service for" + service.getMemberCard().getMemberName());
    		Date memberBirthDay = service.getMemberCard().getMemberBirth();
    		Date sendTime = makeSendTimeToHour(memberBirthDay, sendBirthDayMessageHour);
        	if(verifySendTime(sendTime) && TemplateTargetType.BIRTHDAY.getName().equals(targetType)){
        		String content = YounionUtil.generateMessageContent(service.getTemplate().getContent(), service.getMemberCard());
        		saveMessage(service, sendTime, content, "birthday");
        	}
    	}
    }
    
    private void handleNoCostService() throws Exception{
    	Collection<MembercardServiceVO> noCostMemberCards = retrieveNoCostMemberCards();
    	logger.info("Found " + noCostMemberCards.size() + " guy have no cost in " + noCostTime +" days");
    	for (Iterator<MembercardServiceVO> iterator = noCostMemberCards.iterator(); iterator.hasNext();) { 
    		MembercardServiceVO service = (MembercardServiceVO) iterator.next(); 
    		Date sendTime = makeSendTimeToHour(new Date(), sendSlientMessageHour);
    		if(noCostCount > this.retrieveNotificationCount(service, noCostTime)){
    			saveMessage(service, sendTime, generateNoCostMsgContent(service), "no cost");
    		}
    	}
    }
    
    private void handleNoRechargeService() throws Exception{
    	Collection<MembercardServiceVO> noRechargeMemberCards = retrieveNoRechargeMemberCards();
    	logger.info("Found " + noRechargeMemberCards.size() + " guy have no cost in " + noCostTime +" days");
    	for (Iterator<MembercardServiceVO> iterator = noRechargeMemberCards.iterator(); iterator.hasNext();) { 
    		MembercardServiceVO service = (MembercardServiceVO) iterator.next(); 
    		Date sendTime = makeSendTimeToHour(new Date(), sendSlientMessageHour);
    		if(this.noRechargeCount > this.retrieveNotificationCount(service, this.noRechargeTime)){
    			saveMessage(service, sendTime, generateNoRechargeMsgContent(service), "no recharge");
    		}
    	}
    }
    
    private void handleLessRemain() throws Exception{
    	Collection<MembercardServiceVO> lessRemainMemberCards = retrieveLessRemainMemberCards();
    	logger.info("Found " + lessRemainMemberCards.size() + " guy less then ￥" + noLessRemainCount +"");
    	for (Iterator<MembercardServiceVO> iterator = lessRemainMemberCards.iterator(); iterator.hasNext();) { 
    		MembercardServiceVO service = (MembercardServiceVO) iterator.next(); 
    		Date sendTime = makeSendTimeToHour(new Date(), sendSlientMessageHour);
    		if(this.noLessRemainTime > this.retrieveNotificationCount(service, noLessRemainRange)){
    			saveMessage(service, sendTime, generateLessRemainMsgContent(service), "no recharge");
    		}
    	}
    }
    
    private Collection<MembercardServiceVO> retrieveBirthDayComeMemberCards() throws BaseException{
    	Map paramMap = Maps.newHashMap();
    	return membercardServiceService.selectBirthDayComes(paramMap);
    }
    
    private Collection<MembercardServiceVO> retrieveNoRechargeMemberCards() throws BaseException{
    	Map paramMap = Maps.newHashMap();
    	paramMap.put("interval", noRechargeTime);
    	return membercardServiceService.selectNoRecharge(paramMap);
    }
    
    private Collection<MembercardServiceVO> retrieveNoCostMemberCards() throws BaseException{
    	Map paramMap = Maps.newHashMap();
    	paramMap.put("interval", noCostTime);
    	return membercardServiceService.selectNoCost(paramMap);
    }
    
    private Collection<MembercardServiceVO> retrieveRealTimeMemberCards() throws BaseException{
    	Map paramMap = Maps.newHashMap();
    	paramMap.put("notNullSendTime", true);
    	return membercardServiceService.getByMap(paramMap);
    }
    
    private Collection<MembercardServiceVO> retrieveLessRemainMemberCards() throws BaseException{
    	Map paramMap = Maps.newHashMap();
    	paramMap.put("Money", noLessRemainCount);
    	return membercardServiceService.selectLessRemain(paramMap);
    }
    
    private SendMsgVO createSMS(Date sendTime, MsgTemplateVO template, MemberCardVO card, String content) throws BaseException{
    	RegisterUserVO user = registerUserService.getByMemberCard(card);
    	return YounionUtil.createSMS(sendTime, template, card, content, user);
    }
    
    private MessageVO createMSG(Date sendTime, MsgTemplateVO template, MemberCardVO card, String content) throws BaseException{
    	RegisterUserVO user = registerUserService.getByMemberCard(card);
    	return  YounionUtil.createMSG(sendTime, template, card, content, user);
    }
    
    private Boolean verifySendTime(Date sendTime){
    	if(sendTime == null) return false;
        long nowMillis = new DateTime(System.currentTimeMillis()).withTime(0, 0, 0, 0).getMillis();
        long sendTimeMillis = new DateTime(sendTime).withTime(0, 0, 0, 0).getMillis();
        return nowMillis == sendTimeMillis;
    }
    
    private Date makeSendTimeToHour(Date date, Integer hour){
    	if(date == null) return null;
    	DateTime round = new DateTime().withTime(hour, 0, 0, 0);
    	return round.toDate();
    }
    
    private String generateNoCostMsgContent(MembercardServiceVO service){
    	String content = YounionUtil.generateMessageContent(service.getTemplate().getContent(), service.getMemberCard());
    	if(StringUtils.isBlank(content)){
    		return noCostTemplate.replace("{CARDNAME}", service.getMemberCard().getCustomerName())
    		.replace("{SEX}", service.getMemberCard().getMemberSex() == 1 ? "先生" : "女士" )
    		.replace("{DAY}", noCostTime.toString());
    	}else{
    		if(content.contains(Template.DAY.getTitleValiable()))
    			content = content.replaceAll(Template.DAY.getTitleValiablePattern(), noCostTime.toString());
    	}
    	return content;
    }
    
    private String generateNoRechargeMsgContent(MembercardServiceVO service){
    	String content = YounionUtil.generateMessageContent(service.getTemplate().getContent(), service.getMemberCard());
    	if(StringUtils.isBlank(content)){
    		return noRechargeTemplate.replace("{CARDNAME}", service.getMemberCard().getCustomerName())
        	.replace("{SEX}", service.getMemberCard().getMemberSex() == 1 ? "先生" : "女士" )
        	.replace("{DAY}", noRechargeTime.toString());
    	}else{
    		if(content.contains(Template.DAY.getTitleValiable()))
    			content = content.replaceAll(Template.DAY.getTitleValiablePattern(), noRechargeTime.toString());
    	}
    	return content;
    }
    
    private String generateLessRemainMsgContent(MembercardServiceVO service){
    	String content = YounionUtil.generateMessageContent(service.getTemplate().getContent(), service.getMemberCard());
    	if(StringUtils.isBlank(content)){
    		return LessRemainCountTemplate.replace("{CARDNAME}", service.getMemberCard().getCustomerName())
        	.replace("{SEX}", service.getMemberCard().getMemberSex() == 1 ? "先生" : "女士" )
        	.replace("{MONEY}", service.getMemberCard().getCardBalance().toString());
    	}
    	return content;
    }
    
    private Integer retrieveNotificationCount(MembercardServiceVO service, Integer range) throws BaseException, IllegalAccessException, InvocationTargetException, NoSuchMethodException{
    	NotificationTaskLogVO param = new NotificationTaskLogVO();
    	param.setService(service);
    	Map paramMap = MapCollectionUtils.removeEmptyEntry(PropertyUtils.describe(param));
    	paramMap.put("interval", range);
    	return notificationTaskLogService.getCountByMap(paramMap);
    }
	
	public Integer getSendBirthDayMessageHour() {
		return sendBirthDayMessageHour;
	}

	public void setSendBirthDayMessageHour(Integer sendBirthDayMessageHour) {
		this.sendBirthDayMessageHour = sendBirthDayMessageHour;
	}

	public Integer getSendSlientMessageHour() {
		return sendSlientMessageHour;
	}

	public void setSendSlientMessageHour(Integer sendSlientMessageHour) {
		this.sendSlientMessageHour = sendSlientMessageHour;
	}

	public Boolean getEnableBirthDay() {
		return enableBirthDay;
	}

	public void setEnableBirthDay(Boolean enableBirthDay) {
		this.enableBirthDay = enableBirthDay;
	}

	public Boolean getEnableNoCost() {
		return enableNoCost;
	}

	public void setEnableNoCost(Boolean enableNoCost) {
		this.enableNoCost = enableNoCost;
	}

	public Boolean getEnableNoRecharge() {
		return enableNoRecharge;
	}

	public void setEnableNoRecharge(Boolean enableNoRecharge) {
		this.enableNoRecharge = enableNoRecharge;
	}

	public Boolean getEnableLessRemain() {
		return enableLessRemain;
	}

	public void setEnableLessRemain(Boolean enableLessRemain) {
		this.enableLessRemain = enableLessRemain;
	}

	public Boolean getEnableRealTime() {
		return enableRealTime;
	}

	public void setEnableRealTime(Boolean enableRealTime) {
		this.enableRealTime = enableRealTime;
	}

	public Integer getNoCostTime() {
		return noCostTime;
	}

	public void setNoCostTime(Integer noCostTime) {
		this.noCostTime = noCostTime;
	}

	public Integer getNoRechargeTime() {
		return noRechargeTime;
	}

	public void setNoRechargeTime(Integer noRechargeTime) {
		this.noRechargeTime = noRechargeTime;
	}

	public Integer getNoLessRemainCount() {
		return noLessRemainCount;
	}

	public void setNoLessRemainCount(Integer noLessRemainCount) {
		this.noLessRemainCount = noLessRemainCount;
	}

	public String getNoCostTemplate() {
		return noCostTemplate;
	}

	public void setNoCostTemplate(String noCostTemplate) {
		this.noCostTemplate = noCostTemplate;
	}

	public String getNoRechargeTemplate() {
		return noRechargeTemplate;
	}

	public void setNoRechargeTemplate(String noRechargeTemplate) {
		this.noRechargeTemplate = noRechargeTemplate;
	}

	public String getLessRemainCountTemplate() {
		return LessRemainCountTemplate;
	}

	public void setLessRemainCountTemplate(String lessRemainCountTemplate) {
		LessRemainCountTemplate = lessRemainCountTemplate;
	}
	
	public ISendMsgService getSendMsgService() {
		return sendMsgService;
	}

	public void setSendMsgService(ISendMsgService sendMsgService) {
		this.sendMsgService = sendMsgService;
	}

	public IMembercardServiceService getMembercardServiceService() {
		return membercardServiceService;
	}

	public void setMembercardServiceService(
			IMembercardServiceService membercardServiceService) {
		this.membercardServiceService = membercardServiceService;
	}

	public IMessageService getMessageService() {
		return messageService;
	}

	public void setMessageService(IMessageService messageService) {
		this.messageService = messageService;
	}

	public INotificationTaskLogService getNotificationTaskLogService() {
		return notificationTaskLogService;
	}

	public void setNotificationTaskLogService(
			INotificationTaskLogService notificationTaskLogService) {
		this.notificationTaskLogService = notificationTaskLogService;
	}

	public Integer getNoCostCount() {
		return noCostCount;
	}

	public void setNoCostCount(Integer noCostCount) {
		this.noCostCount = noCostCount;
	}

	public Integer getNoRechargeCount() {
		return noRechargeCount;
	}

	public void setNoRechargeCount(Integer noRechargeCount) {
		this.noRechargeCount = noRechargeCount;
	}

	public Integer getNoLessRemainTime() {
		return noLessRemainTime;
	}

	public void setNoLessRemainTime(Integer noLessRemainTime) {
		this.noLessRemainTime = noLessRemainTime;
	}

	public Integer getNoLessRemainRange() {
		return noLessRemainRange;
	}

	public void setNoLessRemainRange(Integer noLessRemainRange) {
		this.noLessRemainRange = noLessRemainRange;
	}

	public IRegisterUserService getRegisterUserService() {
		return registerUserService;
	}

	public void setRegisterUserService(IRegisterUserService registerUserService) {
		this.registerUserService = registerUserService;
	}

	public static void main(String[] args){
		DateTime round = new DateTime().withTime(10, 0, 0, 0);
		System.out.println(round);
	}
	
}
